
// let arrLen = .length;

export default class C_RandomUtils {
    /**
    * 获取一个区间的随机数
    * @param $from 最小值
    * @param $end 最大值
    * @returns {number}
    */
    public limit($from: number, $end: number): number {
        // $from = Math.min($from, $end);
        // $end = Math.max($from, $end);
        var range: number = $end - $from;
        return $from + Math.random() * range;
    }

    /**
     * 获取一个区间的随机数(整数)
     * @param $from 最小值
     * @param $end 最大值
     * @returns {number}
     */
    public limitInteger($from: number, $end: number): number {
        return Math.floor(this.limit($from, $end + 1));
    }

    /**
     * 在一个数组中随机获取一个元素
     * @param arr 数组
     * @returns {any} 随机出来的结果
     */
    public randomArray<T>(arr: Array<T>): T {
        var index: number = Math.floor(Math.random() * arr.length);
        return arr[index];
    }

    /**
     * 将传进来的数值乱序
     * @param arr 
     */
    public shuffle<T>(arr: Array<T>): Array<T> {
        for (let i = arr.length - 1; i >= 0; i--) {
            let rIndex = Math.floor(Math.random() * (i + 1));
            let temp = arr[rIndex];
            arr[rIndex] = arr[i];
            arr[i] = temp;
        }
        return arr;
    }

    /**
     * 加权随机算法，获取带有权值的随机元素 
     * @param arr 数组
     * @param totalWeight 总的权重值,如果没有会自动计算
     * @returns {any} 随机出来的结果
     */
    public randomArrayByWeight<T extends { weight: number }>(arr: Array<T>, totalWeight?: number): T {
        let arrLen = arr.length;
        if (!totalWeight) {//如果没有指定总权重,自动计算总权重
            totalWeight = 0;
            for (let i = 0; i < arrLen; i++) {
                totalWeight += arr[i].weight;;
            }
        }
        let random = Math.random() * totalWeight;
        for (let i = 0; i < arrLen; i++) {
            random -= arr[i].weight;
            if (random <= 0) {
                return arr[i];
            }
        }
    }
    /**
     * 加权随机算法，获取带有权值的随机元素 
     * @param arr 数组
     * @param seed 随机种子
     * @param totalWeight 总的权重值,如果没有会自动计算
     * @returns {any} 随机出来的结果
     */
    public randomArrayByWeightAndSeed<T extends { weight: number }>(arr: Array<T>, seed: number, totalWeight?: number): T {
        let arrLen = arr.length;
        if (!totalWeight) {//如果没有指定总权重,自动计算总权重
            totalWeight = 0;
            for (let i = 0; i < arrLen; i++) {
                totalWeight += arr[i].weight;;
            }
        }

        let random = cc.math.pseudoRandom(seed) * totalWeight;
        for (let i = 0; i < arrLen; i++) {
            random -= arr[i].weight;
            if (random <= 0) {
                return arr[i];
            }
        }
    }
    /**
     * 
     * @param cnt 第几次随机
     * @param targetRate 目标概率
     */
    judgeSpecialRandom(cnt: number, targetRate: number) {
        //根据目标概率获得每次随机的概率
        let timesRate = PRDRandom.P2C(targetRate);
        let result = Math.random() < timesRate * (cnt + 1);
        CC_DEBUG && console.log('第' + (cnt + 1) + '次  目标概率\uFF1A' + targetRate + '  实际概率\uFF1A' + timesRate * (cnt + 1) + '  ' + result);
        return result;
    }
    /**
     * 加权随机算法，获取带有权值的随机元素的索引
     * @param arr 数组
     * @param totalWeight 总的权重值,如果没有会自动计算
     * @returns {any} 随机出来的结果
     */
    public randomArrayIndexByWeight<T extends { weight: number }>(arr: Array<T>, totalWeight?: number): number {
        let arrLen = arr.length;
        if (!totalWeight) {//如果没有指定总权重,自动计算总权重
            totalWeight = 0;
            for (let i = 0; i < arrLen; i++) {
                totalWeight += arr[i].weight;
            }
        }
        let random = Math.random() * totalWeight;
        for (let i = 0; i < arrLen; i++) {
            random -= arr[i].weight;
            if (random <= 0) {
                return i;
            }
        }
    }

    /**
     * 加权随机算法，获取带有权值的随机元素数组，去重
     * @param arr 数组
     * @param count 获取的随机数量
     * @param isRemove 需要忽视的数据
     * @returns {T} 随机出来的结果
     */
    public randomArrayCountByWeight<T extends { weight: number }>(arr: Array<T>, count: number, isRemove?: Function): T[] {
        const targetArry: T[] = [];
        const tempArr = arr.concat([]);
        if (isRemove) {
            for (let i = tempArr.length - 1; i >= 0; i--) {
                if (isRemove(tempArr[i])) {
                    tempArr.splice(i, 1);
                }
            }
        }
        count = Math.min(tempArr.length, count);
        for (let i = 0; i < count; i++) {
            let index = this.randomArrayIndexByWeight(tempArr);
            targetArry.push(tempArr.splice(index, 1)[0]);
        }
        return targetArry;
    }
}

var cache = {};
class PRDRandom {
    protected times: number;
    protected c: number;
    constructor(t, n) {
        void 0 === n && (n = 0);
        this.times = n;
        this.c = 0;
        this.c = PRDRandom.P2C(t);
    }
    draw() {
        this.times++;
        var e = Math.random() < this.times * this.c;
        e && (this.times = 0);
        return e;
    };
    public static P2C(rate: number) {
        if (cache[rate])
            return cache[rate];
        if (rate <= 0)
            return 0;
        for (var t = 0, n = 0, i = rate, r = 0; ;) {
            r = (i + t) / 2;
            var a = this.C2P(r);
            if (Math.abs(a - n) <= 1e-14)
                break;
            a > rate ? i = r : t = r;
            n = a;
        }
        cache[rate] = r;
        return r;
    };
    public static C2P(e) {
        for (var t = 0, n = 0, o = 0, i = Math.ceil(1 / e), r = 1; r <= i; r++) {
            n += o = (1 - n) * Math.min(1, e * r);
            t += o * r;
        }
        return 1 / t;
    };
}